package com.alisls.demo.springcloud.service.user.service.impl.user;

import com.alisls.demo.springcloud.common.core.util.IdWorker;
import com.alisls.demo.springcloud.service.user.config.ServiceUserProp;
import com.alisls.demo.springcloud.service.user.dao.user.UserDAO;
import com.alisls.demo.springcloud.service.user.dto.user.UserDTO;
import com.alisls.demo.springcloud.service.user.dto.user.UserPwdDTO;
import com.alisls.demo.springcloud.service.user.entity.RoleDO;
import com.alisls.demo.springcloud.service.user.entity.UserDO;
import com.alisls.demo.springcloud.service.user.service.user.UserService;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
 * 用户Service实现
 *
 * @author Ke Wang
 */
@Service("userService")
@AllArgsConstructor
@Log4j2
public class UserServiceImpl implements UserService {

    private final IdWorker idWorker;

    private final ServiceUserProp serviceUserProp;

    private final PasswordEncoder passwordEncoder;

    private final UserDAO userDAO;

    /**
     * 根据用户标识查询用户
     * @Cacheable声明方法是可缓存的(value = "缓存的名字", key = "缓存Key")
     *
     * @param id
     * @return
     */
    @Override
    @Cacheable(cacheNames = "sys_user", key = "#id")
    public UserDTO getUser(Long id) {
        Optional<UserDO> userDO = userDAO.findById(id);

        UserDTO userDTO = new UserDTO();
        userDO.ifPresent(u -> {
            BeanUtils.copyProperties(u, userDTO);
        });

        return userDTO;
    }

    /**
     * 根据用户名查询用户
     */
    @Override
    public UserDTO getUser(String username) {
        // 根据用户名查询用户 TODO 如何懒加载 roles
        UserDO userDO = userDAO.findByUsername(username);

        log.info("根据用户名查询到用户信息：{}", userDO);

        // 获取用户的角色信息
        List<RoleDO> roles = userDO.getRoles();

        UserDTO userDTO = new UserDTO();
        if (userDO != null) {
            BeanUtils.copyProperties(userDO, userDTO, "roles");
        }

        return userDTO;
    }

    /**
     * 根据用户名查询用户（用户结果带有密码字段）
     */
    @Override
    public UserDTO getUserWithPwd(String username) {
        UserDO userDO = userDAO.findByUsername(username);

        UserDTO userDTO = new UserPwdDTO();
        if (userDO != null) {
            BeanUtils.copyProperties(userDO, userDTO);
        }

        return userDTO;
    }

    /**
     * 保存用户，同时将用户数据保存在Redis中，用用户ID作为Key
     * 注意：Jpa在保存用户前，会根据ID查询用户，之后再保存
     */
    @Override
    @CachePut(cacheNames = "sys_user", key = "#userDTO.id")
    public UserDTO save(UserDTO userDTO) {
        if (userDTO == null) {
            return null;
        }
        // 生成ID
        userDTO.setId(idWorker.nextId());

        // 生成userDO
        UserDO userDO = new UserDO();
        BeanUtils.copyProperties(userDTO, userDO);

        if (userDO.getPassword() == null || userDO.getPassword().trim().length() <= 0) {
            userDO.setPassword(getDefaultPassword());
        }

        // 报错用户
        userDAO.save(userDO);

        return userDTO;
    }

    /**
     * 更新用户，更新用户的同时根据菜单编码更新Redis缓存中的菜单信息
     * 注意：Jpa在修改人员之前会先进行查询，之后再进行修改
     */
    @Override
    @CachePut(cacheNames = "sys_user", key = "#userDTO.id")
    public UserDTO update(UserDTO userDTO) {
        UserDO userDO = new UserDO();
        BeanUtils.copyProperties(userDTO, userDO);

        UserDO newUserDO = userDAO.save(userDO);
        if (log.isDebugEnabled()) {
            log.debug("用户信息修改成功，新的用户数据为{}", newUserDO);
        }
        return userDTO;
    }

    /**
     * 创建用户时的默认密码
     *
     * @return
     */
    @Override
    public String getDefaultPassword() {
        String password = serviceUserProp.getPassword();
        return passwordEncoder.encode(password);
    }

}
